package cn.bearspark.framework.web.starter.context;

import cn.bearspark.common.enumeration.RequestHeaderNameEnum;

import java.util.HashMap;
import java.util.Map;

/**
 * (bear-spark) 请求的上下文类，用于存放请求头携带的信息
 *
 * @author f
 */
public class BSRequestContext {

    /**
     * 本地线程存放的资源集合
     * <p>
     * 这个实现类实现了父子线程之间的线程本地变量传递
     * <p>
     * 使用异步操作时创建的子线程会拷贝主线程的 threadLocal
     */
    private static final ThreadLocal<Map<Object, Object>> RESOURCES = new InheritableThreadLocal<>() {
        // 初始化一个新的 HashMap
        @Override
        protected Map<Object, Object> initialValue() {
            return new HashMap<>();
        }

        // 获取子线程的集合时会把父线程的集合拷贝一份
        @Override
        protected Map<Object, Object> childValue(Map<Object, Object> parentValue) {
            if (parentValue != null) {
                return (Map<Object, Object>) ((HashMap<Object, Object>) parentValue).clone();
            } else {
                return null;
            }
        }
    };

    /**
     * 获取用户 id
     */
    public static Long getUserId() {
        Object userId = get(RequestHeaderNameEnum.USER_ID.getName());
        return userId == null ? null : (Long) userId;
    }

    /**
     * 设置用户 id
     *
     * @param userId 用户 id
     */
    public static void setUserId(Long userId) {
        set(RequestHeaderNameEnum.USER_ID.getName(), userId);
    }

    /**
     * 设置资源
     *
     * @param key   资源对应的键
     * @param value 指定的资源
     */
    public static void set(String key, Object value) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        if (value == null) {
            RESOURCES.get().remove(key);
        }
        RESOURCES.get().put(key, value);
    }

    /**
     * 获取资源
     *
     * @param key 资源对应的键
     * @return 指定的资源
     */
    public static Object get(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        return RESOURCES.get().get(key);
    }

    /**
     * 清除线程本地资源，防止内存泄漏
     */
    public static void clear() {
        RESOURCES.remove();
    }

}
